template<typename Type = int> class SLLIter;
template<typename Type> class SLList
{
	struct node
	{
		Type data;
		node *next;
	};
	node *head;
	unsigned int csize;
	friend class SLLIter<Type>;
public:
	SLList();
	~SLList();
	SLList<Type>& operator=(const SLList<Type>& that);
	SLList(const SLList<Type>& that);
	void addHead(const Type& v);
	void clear();
	void insert(SLLIter<Type>& index, const Type& v);
	void remove(SLLIter<Type>& index);
	inline unsigned int size() const;
	node* Helper(node *v);
};
template<typename Type>
SLList<Type>::SLList()
{
	head = nullptr;
	csize = 0;
}

template<typename Type>
SLList<Type>::~SLList()
{
	clear();
}

template<typename Type>
SLList<Type>& SLList<Type>::operator=(const SLList<Type>& that)
{
	if(&that != this)
	{
		clear();
		Helper(that.head);
	}
	return *this;
}

template<typename Type>
typename SLList<Type>::node* SLList<Type>::Helper(node *v)
{
	if(v == nullptr)
		return v;
	else
	{
		Helper(v->next);
		addHead(v->data);
		return v;
	}

}

template<typename Type>
SLList<Type>::SLList(const SLList<Type>& that)
{
	head = nullptr;
	*this = that;
}

template<typename Type>
void SLList<Type>::addHead(const Type& v)
{
	node *temp = new node;
	temp->data = v;
	temp->next = head;
	head = temp;
	csize++;
}

template<typename Type>
void SLList<Type>::clear()
{
	node *temp;
	while(head != nullptr)
	{
		temp = head;
		head = temp->next;
		delete temp;
	}
	csize = 0;
}

template<typename Type>
void SLList<Type>::insert(SLLIter<Type>& index, const Type& v)
{
	if(index.c == nullptr)
		return;
	if(index.c == head)
	{
		node *temp = new node;
		temp->data = v;
		temp->next = head;
		head = temp;
		index.c = head;
		csize++;
	}
	else
	{
		node *temp = new node;
		temp->data = v;
		temp->next = index.c;
		index.p->next = temp;
		index.c = temp;
		csize++;
	}


}

template<typename Type>
void SLList<Type>::remove(SLLIter<Type>& index)
{
	if(index.c == nullptr)
	{
		return;
	}
	else if(index.c == head)
	{
		if(head->next == nullptr)
		{
			delete index.c;
			index.c = nullptr;
			head = nullptr;
			csize--;
		}
		else
		{
			head = head->next;
			delete index.c;
			index.c = head;
			csize--;
		}
	}
	else
	{
		index.p->next = index.c->next;
		delete index.c;
		index.c = index.p->next;
		csize--;
	}



}

template<typename Type>
inline unsigned int SLList<Type>::size() const
{
	return csize;
}

template<typename Type> class SLLIter
{
	friend class SLList<Type>;
	typename SLList<Type>::node * c;
	typename SLList<Type>::node * p;
	SLList<Type> *list;
public:
	SLLIter(SLList<Type>& listToIterate);
	void begin();
	bool end() const;
	SLLIter<Type>& operator++();
	Type& current() const;
};

template<typename Type>
SLLIter<Type>::SLLIter(SLList<Type>& listToIterate)
{
	list = &listToIterate;
	this->p = nullptr;
	this->c = nullptr;
}

template<typename Type>
void SLLIter<Type>::begin()
{
	this->p = nullptr;
	this->c = list->head;
}

template<typename Type>
bool SLLIter<Type>::end() const
{
	if(this->c != nullptr)
		return false;
	else if (this->c == nullptr)
	{
		return true;
	}
	return false;
}

template<typename Type>
SLLIter<Type>& SLLIter<Type>::operator++()
{
	if(this->c == nullptr)
		return *this;
	this->p = this->c;
	this->c = this->c->next;
	return *this;
}

template<typename Type>
Type& SLLIter<Type>::current() const
{
	return c->data;
}

